#pragma once

#include "ThreadPool.hpp"
#include "InetAddr.hpp"

#include <unordered_set>
#include <functional>
#include <vector>
#include <string>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>


using task_t = std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }
    void CheckOnlineUser(InetAddr &who)
    {
        for (auto &user : _user_online)
        {
            if (user == who)
                return;
        }
        _user_online.push_back(who);
    }
    void Offline(InetAddr &who)
    {
        auto it = _user_online.begin();
        for (; it != _user_online.end(); it++)
        {
            if (*it == who)
            {
                _user_online.erase(it);
                break;
            }
        }
    }
    void Task(int sockfd, std::string message, InetAddr& user)
    {
        //细节处理：一个人向群聊中发了消息，然后有人退出群聊，这个退出群聊的人应该先看到消息然后退出
        //如果不加锁，对在线用户列表_user_online不进行保护，一个线程正在处理上一条发送的信息，
        //有人退出了，另一个线程对_user_online中的用户做删除，这不就出现了问题了吗
        //所以需要加锁，对临界资源_user_online进行保护
        pthread_mutex_lock(&_mutex); 
        //1.先判断给服务端发消息的主机是否在用户列表中，不在先添加到用户列表中，在则转发消息
        CheckOnlineUser(user);
        //2.判断消息是否是退出信息"Quit"，如果是将该主机从用户列表中删除
        if(message == "Quit") Offline(user);

        //如果是"Quit"退出信息，我们也将"Quit"信息发送给其他人，让其他人看到有人退出群聊了
        //给用户列表中的人发消息
        std::string send_message = user.AddrStr() + message;//优化：将发送这条消息的人的名字也添加上，发送到群聊中
        auto it = _user_online.begin();
        while(it != _user_online.end())
        {
            struct sockaddr_in addr = it->Addr();
            int n = sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr*)&addr, sizeof(addr));
            ++it;
        }
        pthread_mutex_unlock(&_mutex);
    }
    void Forward(int sockfd, std::string message, InetAddr& user)
    {
        task_t task = std::bind(&Route::Task, this, sockfd, message, user);
        ThreadPool<task_t>::GetInstance()->Equeue(task);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }
private:
    std::vector<InetAddr> _user_online;//用来维护在线的用户
    pthread_mutex_t _mutex;
};